package com.deadline.statebutton;

import ohos.agp.window.service.Display;
import ohos.agp.window.service.DisplayAttributes;
import ohos.agp.window.service.DisplayManager;
import ohos.app.Context;
import ohos.agp.utils.Color;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.element.ShapeElement;
import ohos.global.resource.NotExistException;
import ohos.global.resource.ResourceManager;
import ohos.global.resource.WrongTypeException;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.multimodalinput.event.TouchEvent;

import java.io.IOException;
import java.util.Optional;

public class StateButton extends Button implements Component.TouchEventListener {
    private static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x000110, "StateButton");

    private ResourceManager resManager;
    // button的name
    private String buttonName;

    // 抬起时形状(with radius/round radius/different radius)
    private ShapeElement upElement;

    // 移出button时形状(with radius/round radius/different radius)
    private ShapeElement moveOutElement;

    // 按下时形状(with radius/round radius/different radius)
    private ShapeElement downElement;

    // 抬起时颜色(with radius/round radius/different radius)
    private RgbColor upColor;

    // 移出button时颜色(with radius/round radius/different radius)
    private RgbColor moveOutColor;

    // 按下时颜色(with radius/round radius/different radius)
    private RgbColor downColor;

    private Color orange;

    // CHANGE TEXT COLOR的字体颜色是否可以改变
    private boolean changeTextColorCount = true;

    // CHANGE BACKGROUND COUNT的背景颜色是否可以改变
    private boolean changeBackGroundCount = true;

    // WITH DASH COUNT的边框和字体颜色是否可以改变
    private boolean withDashCount = true;

    // WITH STROKE COUNT的边框和字体颜色是否可以改变
    private boolean withStrokeCount = true;

    // 是否移出button范围
    private boolean moveOutOfButtonFlag = false;

    // 当前点击的button的高度
    private double buttonHeight;

    // 按下时触摸X坐标
    private double downTouchY;

    // button左边界X坐标
    private float leftX;

    // button右边界X坐标
    private float rightX;

    // button上边界Y坐标
    private double topY;

    // button下边界Y坐标
    private double bottomY;

    /**
     * 单参构造
     *
     * @param context
     */
    public StateButton(Context context) {
        super(context);
    }

    /**
     * 双参构造,默认走这个
     *
     * @param context
     * @param attrSet
     */
    public StateButton(Context context, AttrSet attrSet) {
        super(context, attrSet);

        // 获取屏幕高度和宽度
        Optional<Display> display = DisplayManager.getInstance().getDefaultDisplay(this.getContext());
        if (display.isPresent()) {
            DisplayAttributes displayAttributes = display.get().getAttributes();
        }

        // 初始化button
        initButton(attrSet);

        // 设置监听事件
        this.setTouchEventListener(this::onTouchEvent);
    }

    private void initButton(AttrSet attrSet) {
        buttonName = attrSet.getAttr("name").get().getStringValue();
        resManager = this.getResourceManager();
        try {
            orange = new Color(resManager.getElement(ResourceTable.Color_orange).getColor());
        } catch (IOException e) {
            HiLog.error(LABEL, e + "");
        } catch (NotExistException e) {
            HiLog.error(LABEL, e + "");
        } catch (WrongTypeException e) {
            HiLog.error(LABEL, e + "");
        }
    }

    /**
     * 全参构造
     *
     * @param context
     * @param attrSet
     * @param styleName
     */
    public StateButton(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
    }

    /**
     * 触摸事件
     *
     * @param cpt
     * @param touchEvent
     * @return boolean
     */
    @Override
    public boolean onTouchEvent(Component cpt, TouchEvent touchEvent) {
        switch (touchEvent.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN:

                // 初次按下设置标记: 是否移出button范围
                moveOutOfButtonFlag = false;
                buttonHeight = this.getHeight();
                downTouchY = touchEvent.getPointerScreenPosition(0).getY();

                // 获取button横坐标范围
                leftX = this.getLeft();
                rightX = this.getRight();

                // 计算button纵坐标范围 这里不用this.getTop,this.getBottom,返回值为距父组件的距离,该返回值不是距屏幕顶部的值
                /*
                public int getTop()
                Obtains the top edge position of a component relative to the parent layout.
                这里的计算,假设点击位置都在button高度中心点击,移动偏移1/2高度,就当做移出button范围
                最上边的label和屏幕顶端状态栏还有高度
                 */
                topY = downTouchY - buttonHeight / 2f;
                bottomY = downTouchY + buttonHeight / 2f;

                downElement = new ShapeElement();
                downColor = new RgbColor(46, 64, 320);
                if ("changeTextColor".equals(buttonName)) {
                    if (!changeTextColorCount) {
                        return false;
                    }
                    this.setTextColor(Color.RED);
                } else if ("changeBackGround".equals(buttonName)) {
                    if (!changeBackGroundCount) {
                        return false;
                    }
                    ShapeElement cBackElement = (ShapeElement) cpt.getBackgroundElement();
                    cBackElement.setRgbColor(downColor);
                } else if ("withRadius".equals(buttonName)) {
                    downElement.setCornerRadiiArray(new float[]{30, 30, 30, 30, 30, 30, 30, 30});
                    downElement.setRgbColor(downColor);
                    this.setBackground(downElement);
                } else if ("roundRadius".equals(buttonName)) {
                    downElement.setCornerRadiiArray(new float[]{100, 100, 100, 100, 100, 100, 100, 100});
                    downElement.setRgbColor(downColor);
                    this.setBackground(downElement);
                } else if ("differentRadius".equals(buttonName)) {
                    downElement.setCornerRadiiArray(new float[]{0, 0, 20, 20, 30, 30, 80, 80});
                    downElement.setRgbColor(downColor);
                    this.setBackground(downElement);
                } else if ("keepStroke".equals(buttonName)) {
                    ShapeElement keepStrokeEle = (ShapeElement) cpt.getBackgroundElement();
                    keepStrokeEle.setRgbColor(downColor);
                    this.setBackground(keepStrokeEle);
                } else if ("strokeBackground".equals(buttonName)) {
                    ShapeElement strokeBackgroundEle = (ShapeElement) cpt.getBackgroundElement();
                    strokeBackgroundEle.setStroke(0, strokeBackgroundEle.getStrokeColor());
                    strokeBackgroundEle.setRgbColor(downColor);
                    this.setBackground(strokeBackgroundEle);
                } else if ("strokeBackgroundAnimation".equals(buttonName)) {
                    ShapeElement strokeBackgroundAnimation = (ShapeElement) cpt.getBackgroundElement();
                    strokeBackgroundAnimation.setStroke(0, strokeBackgroundAnimation.getStrokeColor());
                    strokeBackgroundAnimation.setRgbColor(downColor);
                    this.setBackground(strokeBackgroundAnimation);
                } else if ("withDash".equals(buttonName)) {
                    if (!withDashCount) {
                        return false;
                    }
                    ShapeElement withDashElement = (ShapeElement) cpt.getBackgroundElement();
                    withDashElement.setStroke(withDashElement.getStrokeWidth(), RgbColor.fromArgbInt(Color.RED.getValue()));
                    this.setBackground(withDashElement);
                    this.setTextColor(Color.RED);
                } else if ("withStroke".equals(buttonName)) {
                    if (!withStrokeCount) {
                        return false;
                    }
                    ShapeElement withStrokeElement = (ShapeElement) cpt.getBackgroundElement();
                    withStrokeElement.setStroke(withStrokeElement.getStrokeWidth(), RgbColor.fromArgbInt(Color.RED.getValue()));
                    this.setBackground(withStrokeElement);
                    this.setTextColor(Color.RED);
                }
                return true;
            case TouchEvent.PRIMARY_POINT_UP:
                // 控制点移出button后PointUp不生效
                if (moveOutOfButtonFlag) {
                    return true;
                }
                upElement = new ShapeElement();
                upColor = new RgbColor(46, 64, 159);
                if ("changeTextColor".equals(buttonName)) {
                    changeTextColorCount = false;
                    this.setTextColor(orange);
                } else if ("changeBackGround".equals(buttonName)) {
                    changeBackGroundCount = false;
                    ShapeElement cBackElement = (ShapeElement) cpt.getBackgroundElement();
                    cBackElement.setRgbColor(RgbColor.fromArgbInt(Color.RED.getValue()));
                } else if (("withRadius").equals(buttonName)) {
                    upElement.setCornerRadiiArray(new float[]{30, 30, 30, 30, 30, 30, 30, 30});
                    upElement.setRgbColor(upColor);
                    this.setBackground(upElement);
                } else if ("roundRadius".equals(buttonName)) {
                    upElement.setCornerRadiiArray(new float[]{100, 100, 100, 100, 100, 100, 100, 100});
                    upElement.setRgbColor(upColor);
                    this.setBackground(upElement);
                } else if ("differentRadius".equals(buttonName)) {
                    upElement.setCornerRadiiArray(new float[]{0, 0, 20, 20, 30, 30, 80, 80});
                    upElement.setRgbColor(upColor);
                    this.setBackground(upElement);
                } else if ("keepStroke".equals(buttonName)) {
                    ShapeElement keepStrokeEle = (ShapeElement) cpt.getBackgroundElement();
                    keepStrokeEle.setRgbColor(RgbColor.fromArgbInt(Color.BLACK.getValue()));
                    this.setBackground(keepStrokeEle);
                } else if ("strokeBackground".equals(buttonName)) {
                    ShapeElement strokeBackground = (ShapeElement) cpt.getBackgroundElement();
                    strokeBackground.setStroke(10, strokeBackground.getStrokeColor());
                    strokeBackground.setRgbColor(RgbColor.fromArgbInt(Color.BLACK.getValue()));
                    this.setBackground(strokeBackground);
                } else if ("strokeBackgroundAnimation".equals(buttonName)) {
                    ShapeElement strokeBackgroundAnimation = (ShapeElement) cpt.getBackgroundElement();
                    strokeBackgroundAnimation.setStroke(10, strokeBackgroundAnimation.getStrokeColor());
                    strokeBackgroundAnimation.setRgbColor(RgbColor.fromArgbInt(Color.BLACK.getValue()));
                    this.setBackground(strokeBackgroundAnimation);
                } else if ("withDash".equals(buttonName)) {
                    withDashCount = false;
                    ShapeElement withDashElement = (ShapeElement) cpt.getBackgroundElement();
                    withDashElement.setStroke(withDashElement.getStrokeWidth(), RgbColor.fromArgbInt(orange.getValue()));
                    this.setBackground(withDashElement);
                    this.setTextColor(orange);
                    return false;
                } else if ("withStroke".equals(buttonName)) {
                    withStrokeCount = false;
                    ShapeElement withStrokeElement = (ShapeElement) cpt.getBackgroundElement();
                    withStrokeElement.setStroke(withStrokeElement.getStrokeWidth(), RgbColor.fromArgbInt(orange.getValue()));
                    this.setBackground(withStrokeElement);
                    this.setTextColor(orange);
                }
                return true;
            case TouchEvent.POINT_MOVE:
                moveOutElement = new ShapeElement();
                moveOutColor = new RgbColor(63, 78, 180);

                // 移动中的触摸点坐标X
                float newTouchX = touchEvent.getPointerScreenPosition(0).getX();

                // 移动中的触摸点坐标Y
                float newTouchY = touchEvent.getPointerScreenPosition(0).getY();
                if (isOutOfButton(newTouchX, newTouchY)) {
                    moveOutOfButtonFlag = true;
                    if ("changeTextColor".equals(buttonName)) {
                        this.setTextColor(Color.WHITE);
                    } else if ("changeBackGround".equals(buttonName)) {
                        ShapeElement cBackElement = (ShapeElement) cpt.getBackgroundElement();
                        cBackElement.setRgbColor(moveOutColor);
                    } else if (("withRadius").equals(buttonName)) {
                        moveOutElement.setCornerRadiiArray(new float[]{30, 30, 30, 30, 30, 30, 30, 30});
                        moveOutElement.setRgbColor(moveOutColor);
                        this.setBackground(moveOutElement);
                    } else if ("roundRadius".equals(buttonName)) {
                        moveOutElement.setCornerRadiiArray(new float[]{100, 100, 100, 100, 100, 100, 100, 100});
                        moveOutElement.setRgbColor(moveOutColor);
                        this.setBackground(moveOutElement);
                    } else if ("differentRadius".equals(buttonName)) {
                        moveOutElement.setCornerRadiiArray(new float[]{0, 0, 20, 20, 30, 30, 80, 80});
                        moveOutElement.setRgbColor(moveOutColor);
                        this.setBackground(moveOutElement);
                    } else if ("keepStroke".equals(buttonName)) {
                        ShapeElement keepStrokeEle = (ShapeElement) cpt.getBackgroundElement();
                        keepStrokeEle.setRgbColor(RgbColor.fromArgbInt(Color.BLACK.getValue()));
                        this.setBackground(keepStrokeEle);
                    } else if ("strokeBackground".equals(buttonName)) {
                        ShapeElement strokeBackground = (ShapeElement) cpt.getBackgroundElement();
                        strokeBackground.setStroke(10, strokeBackground.getStrokeColor());
                        strokeBackground.setRgbColor(RgbColor.fromArgbInt(Color.BLACK.getValue()));
                        this.setBackground(strokeBackground);
                    } else if ("strokeBackgroundAnimation".equals(buttonName)) {
                        ShapeElement strokeBackgroundAnimation = (ShapeElement) cpt.getBackgroundElement();
                        strokeBackgroundAnimation.setStroke(10, strokeBackgroundAnimation.getStrokeColor());
                        strokeBackgroundAnimation.setRgbColor(RgbColor.fromArgbInt(Color.BLACK.getValue()));
                        this.setBackground(strokeBackgroundAnimation);
                    } else if ("withDash".equals(buttonName)) {
                        ShapeElement withDashElement = (ShapeElement) cpt.getBackgroundElement();
                        withDashElement.setStroke(withDashElement.getStrokeWidth(), RgbColor.fromArgbInt(Color.WHITE.getValue()));
                        this.setBackground(withDashElement);
                        this.setTextColor(Color.WHITE);
                    } else if ("withStroke".equals(buttonName)) {
                        ShapeElement withStrokeElement = (ShapeElement) cpt.getBackgroundElement();
                        withStrokeElement.setStroke(withStrokeElement.getStrokeWidth(), RgbColor.fromArgbInt(Color.WHITE.getValue()));
                        this.setBackground(withStrokeElement);
                        this.setTextColor(Color.WHITE);
                    }
                    return false;
                }
            default:
        }
        return false;
    }

    /**
     * 判断控制点是否在button范围内,X轴计算准确;
     * Y轴计算不准确:这里的计算,假设点击位置都在button高度h的中心点击,
     * 移动偏移1/2高度,就当做移出button范围.
     * bug示例: 当点击位置位于button上边框附近时,向下滑动超过1/2h则会判断为移出button范围,
     * 实际上并未超出button
     * 最上边的label和屏幕顶端状态栏还有高度
     *
     * @param newTouchX
     * @param newTouchY
     * @return boolean
     */
    private boolean isOutOfButton(float newTouchX, float newTouchY) {
        if (newTouchX < leftX) {
            return true;
        } else if (newTouchX > rightX) {
            return true;
        } else if (newTouchY < topY) {
            return true;
        } else if (newTouchY > bottomY) {
            return true;
        }
        return false;
    }
}
